package tree;

import com.sun.org.apache.regexp.internal.RE;
import linearlist.Queue;
import reflect.Persion;

import java.lang.annotation.ElementType;
import java.util.ArrayList;
import java.util.List;


/**
 * @Author Zhouchb
 * @Create 2021-10-2021/10/27 :17:33
 * @Description
 */
public class BinaryTree<Key extends Comparable<Key>,Value > {
    private Node root;//记录根节点
    private int N;//记录树中元素的个数

    //创建BinaryTree对象
    BinaryTree(){ }

    private class Node{
        public Key key;//存储键
        public Value value;//存储值
        public Node left;//记录左子节点
        public Node right;//记录右子节点
        public Node(Key key ,Value value ,Node left,Node right){
            this.key=key;
            this.value=value;
            this.left=left;
            this.right=right;
        }
    }
    //向树中插入一个键值对
    public void put(Key key,Value value){
        root = put(root,key,value);
    }
    //给指定树上，添加一个键值对，并返回添加后的新树
    private Node put(Node x,Key key ,Value value){
        //如果x子树为空
        if (x==null){
            N++;
            x=new Node(key,value,null,null);
            return x;
        }
        //如果x子树不为空
        //比较x节点的键和key的大小
        //如果key小于x节点的键，则继续找x节点的左子树
        int cmp = x.key.compareTo(key);
        if (cmp>0){
                x.left = put(x.left,key,value);
            }
        //如果key大于x节点的键，则继续找x节点的右子树
        else if (cmp<0){
            x.right = put(x.right,key,value);
        }
        //如果key等于x节点的键，则替换x节点的值为value即可
        else{
            x.value=value;
        }
        return x;
    }
    //根据key，从树中找出对应的值
    public Value get(Key key){
       return get(root,key);
    }
    //从指定的树中，找出key对应的值
    public Value get(Node x,Key key){

        if (x==null){
            return null;
        }
        int cmp = x.key.compareTo(key);
        if (cmp>0){
            return get(x.left,key);
        }
        else if (cmp<0){
            return get(x.right,key);
        }
        else  {
            return x.value;
        }

    }

    //根据key ，删除树中对应的键值对
    public void delete(Key key){
        delete(root,key);
    };
    //删除指定树上键为key的键值树，并返回删除后的新树
     private Node delete(Node x,Key key){
        if (x==null){
            return null;
        }
         int cmp = x.key.compareTo(key);
         if (cmp>0){
             x.left= delete(x.left,key);
         }
         else if (cmp<0){
             x.right = delete(x.right,key);
         }
         else {
             N--;

            //如果要删除节点的右节点为空则返回做节点
             if (x.right==null){
                 return x.left;
             }
             if (x.left==null){
                 return x.right;
             }
             //遍历要删节点的右子树的最小值作为替换
             Node minNode = x.right;
             while (minNode.left!=null){
                 minNode = minNode.left;
             }
             //删除有子树中最小的节点
             Node n = x.right;
             while (n.left!= null){
                 if (n.left.left==null){
                     n.left=null;
                 }else {
                     n=n.left;
                 }
             }
             //让x节点的左子树成为minNode的左子树
             minNode.left = x.left;
             //让x节点的右子树成为minNode的右子树
             minNode.right = x.right;
             //让x节点的x节点指向minnode
             x=minNode;
         }
         return x;
     }
     //获取去树中元素的个数
    public int size(){
    return N;
    }
    //查找二叉树最小键
    public Key getMin(){
         return getMin(root).key;
    }
    public Node getMin(Node x ){
         if (x.left!=null){
             return getMin(x.left);
         }else {
             return x;
         }
    }
    //查找二叉树最大键
    public Key getMax(){
        return getMin(root).key;
    }
    public Node getMax(Node x ){
        if (x.right!=null){
            return getMin(x.right);
        }else {
            return x;
        }
    }

    //前序遍历
    public List<Key> preErgodic(){
        List<Key> list = new ArrayList<>();
        preErgodic(root,list);
        return list;
    }
    public void preErgodic(Node x,List<Key> list){
        if (x==null){
            return;
        }
        list.add(x.key);
        preErgodic(x.left,list);
        preErgodic(x.right,list);
    }
    //中序遍历
    public List<Key> midErgodic(){
        List<Key> list = new ArrayList<>();
        midErgodic(root,list);
        return list;
    }
    public void midErgodic(Node x,List<Key> list){
        if (x==null){
            return;
        }
        midErgodic(x.left,list);
        list.add(x.key);
        midErgodic(x.right,list);
    }

    //后序遍历
    public List<Key> afterErgodic(){
        List<Key> list = new ArrayList<>();
        afterErgodic(root,list);
        return list;
    }
    public void afterErgodic(Node x,List<Key> list){
        if (x==null){
            return;
        }
        afterErgodic(x.left,list);
        afterErgodic(x.right,list);
        list.add(x.key);
    }

    //使用层序遍历，获取所有键
    public Queue<Key> layerErgodic(){
        Queue<Key> keys = new Queue<>();
        Queue<Node> nodes = new Queue<>();
        nodes.enqueue(root);
        while (!nodes.isEmpty()){
            Node dequeue = nodes.dequeue();
            keys.enqueue(dequeue.key);
            if (dequeue.left!=null){
                nodes.enqueue(dequeue.left);
            }
            if (dequeue.right!=null){
                nodes.enqueue(dequeue.right);
            }

        }
        return keys;
    }

    //获取指定树的最大深度
    public int maxDepth(){
        return maxDepth(root);
    }
    public int maxDepth(Node x){
    if (x==null){
        return 0;
    }
    //x的最大深度
        int max = 0;
        int maxL = 0;
        int maxR = 0;
        if (x.left != null){
            maxL = maxDepth(x.left);
        }
        if (x.right!=null){
            maxR = maxDepth(x.right);
        }
        //每次返回都会加一
        max = maxL>maxR?maxL+1:maxR+1;
        return max;
    }
}
